/**
 * 
 */
package com.google.code.netz.wfe;

import com.google.code.netz.wfe.api.ILifecycleHandler;
import com.google.code.netz.wfe.api.IWorkflowContext;
import com.google.code.netz.wfe.api.IWorkflowEngine;
import com.google.code.netz.wfe.api.WorkflowException;
import com.google.code.netz.wfe.internal.CloseCaseTask;
import com.google.code.netz.wfe.internal.OpenCaseTask;
import com.google.code.netz.wfe.internal.ResumeCaseTask;
import com.google.code.netz.wfe.internal.SubmitCaseTask;
import com.google.code.netz.wfe.internal.SuspendCaseTask;
import com.google.code.netz.wfe.model.ICase;
import com.google.code.netz.wfe.model.State;
import com.google.code.netz.wfe.model.Transition;

/**
 * @author <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 * @since 1.0
 * @version $Id: CaseLifecycleHandler.java 17 2009-02-09 13:08:49Z rahul.thakur.xdev $
 */
public class CaseLifecycleHandler implements ILifecycleHandler<ICase<?>> {

	/**
	 * Mutex to lock state updates to the Case.
	 */
	private static Object mutex = new Object();

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#resume(com.google.code.netz.wfe.api.IManaged,
	 *      IWorkflowContext)
	 */
	@Override
	public void resume(ICase<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		// TODO: Case status should be updated in a synchronized block
		// Resume Case only if it is suspended
		IWorkflowEngine engine = workflowContext.getWorkflowEngine();
		synchronized (mutex) {
			if (entity.getCurrentState() == State.STATE_SUSPENDED) {
				ResumeCaseTask task = new ResumeCaseTask(entity, engine);
				Transition internalTransition = new Transition("Internal :: Resume Case", task, true);
				engine.fire(internalTransition, engine);
			} else
				throw new WorkflowException(String.format(
						"Case %s could not be resumed, it is not in a suspended state.", entity.getLabel()));
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Opens the specified Case.
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#start(com.google.code.netz.wfe.api.IManaged,
	 *      IWorkflowContext)
	 */
	@Override
	public void start(ICase<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		IWorkflowEngine engine = workflowContext.getWorkflowEngine();
		synchronized (mutex) {
			// TODO: Case status should be updated in a synchronized block
			if (entity.getCurrentState() == State.STATE_DEFAULT) {
				SubmitCaseTask task = new SubmitCaseTask(entity, engine);
				Transition internalTransition = new Transition("Internal :: Submit Case", task, true);
				engine.fire(internalTransition, engine);
			} else if (entity.getCurrentState() == State.STATE_ENABLED) {
				OpenCaseTask task = new OpenCaseTask(entity, null);
				Transition internalTransition = new Transition("Internal :: Open Case", task, true);
				engine.fire(internalTransition, engine);
			} else
				throw new WorkflowException(String.format(
						"Case %s could not be progressed to next state; its current state is %s.", entity.getLabel(),
						entity.getCurrentState().getState()));
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#stop(com.google.code.netz.wfe.api.IManaged,
	 *      IWorkflowContext)
	 */
	@Override
	public void stop(ICase<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		IWorkflowEngine engine = workflowContext.getWorkflowEngine();
		synchronized (mutex) {
			// Case status should be updated in a synchronized block
			// TODO: Evaluated current state of the Case,
			// if the Case completed without error then the state should be set
			// to COMPLETED else should be set to ERROR
			if (entity.getCurrentState() == State.STATE_RUNNING) {
				CloseCaseTask task = new CloseCaseTask(entity, engine);
				Transition internalTransition = new Transition("Internal :: Close Case", task, true);
				engine.fire(internalTransition, engine);
			} else
				throw new WorkflowException(String.format("Case %s could not be stopped, it is not currently running.",
						entity.getLabel()));
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#suspend(com.google.code.netz.wfe.api.IManaged,
	 *      IWorkflowContext)
	 */
	@Override
	public void suspend(ICase<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		IWorkflowEngine engine = workflowContext.getWorkflowEngine();
		synchronized (mutex) {
			// TODO: Case status should be updated in a synchronized block
			if (entity.getCurrentState() == State.STATE_RUNNING) {
				SuspendCaseTask task = new SuspendCaseTask(entity, engine);
				Transition internalTransition = new Transition("Internal :: Suspend Case", task, true);
				engine.fire(internalTransition, engine);
			} else
				throw new WorkflowException(String.format(
						"Case %s could not be suspended, it is not currently running.", entity.getLabel()));
		}
	}

}
